package com.atguigu.gulimall.member.service.impl;

import com.atguigu.common.exception.BizCodeEnum;
import com.atguigu.common.utils.HttpClientUtils;
import com.atguigu.gulimall.member.entity.MemberLevelEntity;
import com.atguigu.gulimall.member.exception.MemberException;
import com.atguigu.gulimall.member.service.MemberLevelService;
import com.atguigu.gulimall.member.vo.MemberUserLoginVo;
import com.atguigu.gulimall.member.vo.UserRegisterVo;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.member.dao.MemberDao;
import com.atguigu.gulimall.member.entity.MemberEntity;
import com.atguigu.gulimall.member.service.MemberService;

import javax.annotation.Resource;


/**
 * @author ShiJieLin
 */
@Service("memberService")
@Slf4j
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {

    @Resource
    private MemberLevelService memberLevelService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberEntity> page = this.page(
                new Query<MemberEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }

    @Override
    public void register(UserRegisterVo vo) throws MemberException {

        // 1.确认是手机号和用户名唯一
        checkPhoneUnique(vo.getPhone());
        checkUserNameUnique(vo.getUserName());

        MemberEntity memberEntity = new MemberEntity();

        // 2.设置默认等级
        MemberLevelEntity levelEntity = memberLevelService.getOne(
                new QueryWrapper<MemberLevelEntity>()
                        .eq("default_status", 1));
        memberEntity.setLevelId(levelEntity.getId());
        // 3.将客户的明文密码加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(vo.getPassword());

        memberEntity.setPassword(encode);
        memberEntity.setCreateTime(new Date());
        memberEntity.setUsername(vo.getUserName());
        memberEntity.setMobile(vo.getPhone());
        memberEntity.setGender(0);
        // 4.保存用户信息
        baseMapper.insert(memberEntity);
    }

    @Override
    public MemberEntity login(MemberUserLoginVo vo) {

        String loginacct = vo.getLoginacct();
        String password = vo.getPassword();

        MemberEntity memberEntity = baseMapper.selectOne(new QueryWrapper<MemberEntity>()
                .eq("username", loginacct).or()
                .eq("mobile", loginacct));
        // 登陆失败
        if (null == memberEntity) {
            return null;
        } else {
            // 比对明文密码和数据库中的是否一致
            String passwordDB = memberEntity.getPassword();
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            boolean matches = encoder.matches(password, passwordDB);
            // 是否验证成功
            memberEntity.setPassword(null);
            return matches ? memberEntity : null;
        }
    }

    @Override
    public MemberEntity login(String accessTokenInfo) throws Exception {

        // 1.从accessTokenInfo中获取出来两个值 access_token 和 oppenid
        Gson gson = new Gson();
        // 2.把accessTokenInfo字符串转换成map集合，根据map里面中的key取出相对应的value
        HashMap accessMap = gson.fromJson(accessTokenInfo, HashMap.class);
        String accessToken = (String) accessMap.get("access_token");
        String openid = (String) accessMap.get("openid");

        // 3.根据openid 微信唯一ID判断用户是注册还是登陆
        MemberEntity memberEntity = baseMapper.selectOne(new QueryWrapper<MemberEntity>()
                .eq("openid", openid));
        // 4.如果为空则是注册
        if (null == memberEntity) {
            // 4.1拿着得到accsess_token 和 openid，再去请求微信提供固定的地址，获取到扫描人信息
            // 访问微信的资源服务器，获取用户信息
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=%s" +
                    "&openid=%s";
            // 拼接请求微信的地址
            String userInfoUrl = String.format(baseUserInfoUrl, accessToken, openid);
            // 4.2发送请求获取用户信息
            String userInfo = HttpClientUtils.get(userInfoUrl);
            // 4.3转化为map
            HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
            log.info("微信请求用户数据成功", userInfo);
            // 昵称
            String nickName = (String) userInfoMap.get("nickname");
            // 性别
            Double sex = (Double) userInfoMap.get("sex");
            // 微信头像
            String headimgurl = (String) userInfoMap.get("headimgurl");
            // 设置默认等级
            MemberLevelEntity levelEntity = memberLevelService.getOne(
                    new QueryWrapper<MemberLevelEntity>()
                            .eq("default_status", 1));

            memberEntity = new MemberEntity();
            memberEntity.setLevelId(levelEntity.getId());
            memberEntity.setNickname(nickName);
            memberEntity.setGender(Integer.valueOf(Double.valueOf(sex).intValue()));
            memberEntity.setHeader(headimgurl);
            memberEntity.setCreateTime(new Date());
            memberEntity.setOpenid(openid);

            this.baseMapper.insert(memberEntity);
        }else {
            memberEntity.setOpenid(openid);
            baseMapper.updateById(memberEntity);
        }
        memberEntity.setPassword(null);
        return memberEntity;
    }

    /**
     * 确认用户名是否唯一
     *
     * @param userName
     */
    private void checkUserNameUnique(String userName) throws MemberException {

        Integer usernameCount = this.baseMapper.selectCount(new QueryWrapper<MemberEntity>()
                .eq("username", userName));
        if (usernameCount > 0) {
            throw new MemberException(BizCodeEnum.USER_EXIST_EXCEPTION);
        }
    }

    /**
     * 确认手机号是否唯一
     *
     * @param phone
     */
    private void checkPhoneUnique(String phone) throws MemberException {

        Integer phoneCount = baseMapper.selectCount(new QueryWrapper<MemberEntity>()
                .eq("mobile", phone));
        if (phoneCount > 0) {
            throw new MemberException(BizCodeEnum.PHONE_EXIST_EXCEPTION);
        }
    }

}